package org.pyq.core.process;

import javassist.*;

import java.io.File;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author pengYongQiang
 * @date 2022/1/7 18:19
 */
public class SqlProcess extends AbsProcess {

    public SqlProcess(Instrumentation instrumentation) {
        super("com.mysql.cj.jdbc.ClientPreparedStatement", instrumentation);
    }

    @Override
    public byte[] invoke(String... params) {
        try {
            return doInvoke(params);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    //前缀
    final static String prefix = "com.paas.nesb.mesh";
    final static String s = "" +
            "               StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();\n" +
            "               java.util.List collect = new java.util.ArrayList();\n" +
            "               for (int i = 0; i < stackTrace.length; i++) {\n" +
            "                    String stackTraceName = stackTrace[i].toString();\n" +
            "                   if(stackTraceName.startsWith(\"" + prefix + "\")){\n" +
            "                      collect.add(stackTraceName);\n" +
            "                   }\n" +
            "               }\n" +
            "               java.util.Collections.reverse(collect);\n" +
            "               String lastClassName = null;\n" +
            "               String pre=\"\";\n" +
            "               for(int i = 0; i < collect.size(); i++){\n" +
            "                   String s = collect.get(i);\n" +
            "                   int i = s.lastIndexOf(\"(\");\n" +
            "                   String substring = s.substring(0, i);\n" +
            "                   int i1 = substring.lastIndexOf(\".\");\n" +
            "                   String className = substring.substring(0, i1);\n" +
            "                   if (className.equals(lastClassName)){\n" +
            "                   }else {\n" +
            "                       pre +=\" \";\n" +
            "                   }\n" +
            "                   s = pre+s;\n" +
            "                   lastClassName = className;\n" +
            "                   System.out.println(s);\n" +
            "               }";

    final static String s1 = "  String sql = toString();\n" +
            "        String prefix = \"com.mysql.cj.jdbc.ClientPreparedStatement:\";\n" +
            "        if (sql.startsWith(prefix)) {\n" +
            "            sql = sql.split(prefix)[1];\n" +
            "        }" +
            "        sql = sql.replace(\"\\n\", \"\");   \n" +
            "        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(\"%s\");\n" +
            "        java.util.regex.Matcher matcher = pattern.matcher(sql);\n" +
            "        if (matcher.matches()){\n" + s +
            "           System.out.println(\"\\r\\n--------------------------------------------\\r\\n\" + sql+ \"\\r\\n--------------------------------------------\");\n" +
            "        }" +
            "";

    final static String s2 = " " +
            "           java.lang.System.out.println();" +
            "";


    @Override
    public byte[] back() {
        try {
            ClassPool pool = ClassPool.getDefault();
            String fulltClassName = "com.classbak." + getClassName() + "Bak";
            CtClass cc = null;
            try {
                cc = pool.getCtClass(fulltClassName);
            } catch (NotFoundException e) {
            }

            if (cc == null) {
                // 1. 创建一个空类
                cc = pool.makeClass(fulltClassName);
            }
            if (cc.isFrozen()) {
                cc.defrost();
            }

            // 2. 新增一个字段 private String name;
            // 字段名为name


            CtField ctField = cc.getDeclaredField("name");
            if (ctField == null) {
                ctField = new CtField(pool.get("java.lang.String"), "name", cc);
                cc.addField(ctField, CtField.Initializer.constant(getClassName()));
            }

            cc.writeFile("D://");
            MyClassLoader myClassLoader = new MyClassLoader("D://" + fulltClassName.replace(".", "//") + ".class");

            Class<?> aClass = Class.forName(fulltClassName, true, myClassLoader);
            Field name = aClass.getDeclaredField("name");
            Object o = aClass.newInstance();
            System.out.println("属性名" + name.getName());

            return cc.toBytecode();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    class MyClassLoader extends ClassLoader {

        String classPath;

        public MyClassLoader(String classPath) {
            this.classPath = classPath;
        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            File file = new File(classPath);
            try {
                byte[] bytes = Files.readAllBytes(Paths.get(file.toURI()));
                return defineClass(null, bytes, 0, bytes.length, null);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return super.findClass(name);
        }
    }

    @Override
    public byte[] reset() {

        byte[] bytes = new byte[0];
        try {
            Class<?> clazz = getClazz();
            String className = getClassName();
            ClassLoader classLoader = clazz.getClassLoader();

            ClassPool classPool = new ClassPool();
            LoaderClassPath loaderClassPath = new LoaderClassPath(classLoader);
            classPool.insertClassPath(loaderClassPath);

            String replace = className.replace("/", ".");
            CtClass cla = classPool.get(replace);

            bytes = cla.toBytecode();
            classPool.removeClassPath(loaderClassPath);
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (CannotCompileException e) {
            e.printStackTrace();
        }
        return bytes;
    }

    /**
     * @return
     * @throws Exception
     */
    private byte[] doInvoke(String... params) throws Exception {

        Class<?> clazz = getClazz();
        String className = getClassName();
        ClassLoader classLoader = clazz.getClassLoader();

        ClassPool classPool = new ClassPool();
        LoaderClassPath loaderClassPath = new LoaderClassPath(classLoader);
        classPool.insertClassPath(loaderClassPath);

        String replace = className.replace("/", ".");
        replace = replace.replace("\\", ".");
        System.out.println("class:" + replace);
        CtClass cla = classPool.get(replace);

        CtClass[] params1 = {
                CtClass.intType,
                classPool.get("com.mysql.cj.protocol.Message"),
                CtClass.booleanType,
                CtClass.booleanType,
                classPool.get("com.mysql.cj.protocol.ColumnDefinition"),
                CtClass.booleanType,
        };
        String executeInternal = "executeInternal";
        System.out.println("改变方法:"+executeInternal);
        CtMethod ctMethod = cla.getDeclaredMethod(executeInternal,params1);

        System.out.println("params:" + params[0]);
        String insert = String.format(s1, params[0]);
        System.out.println("插入:" + insert);
        ctMethod.insertBefore(insert);
        String s = ctMethod.getMethodInfo().toString();
        byte[] bytes = cla.toBytecode();
        classPool.removeClassPath(loaderClassPath);
        return bytes;
    }
}
